function rotate(matrix, direction) {
    return direction === 'clockwise' ? matrix[0].map((_, i, origin) => matrix.map(a => a[i]).reverse()) : matrix[0].map((_, i, origin) => matrix.map(a => a[i])).reverse()
}
var Sudoku = function(data) {
    return {
        isValid: function() {
            for (var i = 0; i < data.length; i++) { if (data[i].length != data[0].length) return false; }
            var N = data.length;
            var pattern = Array.from({ length: N }, (v, i) => i + 1).join(',')
            //check each row
            for (x of data) { if ([].concat(x).sort((a, b) => a - b).join(',') != pattern) return false; }
            //check each column
            var arr = rotate(data);
            for (x of arr) { if (x.sort((a, b) => a - b).join(',') != pattern) return false; }
            //check square
            var size = Math.sqrt(N);
            for (var i = 0; i < N; i += size) {
                var sub = [].concat(data.slice(i, i + size));
                for (var j = 0; j < N; j += size) {
                    var temp = []
                    for (var k = 0; k < size; k++) { temp = temp.concat(sub[k].slice(j, j + size)) }
                    if (temp.sort((a, b) => a - b).join(',') != pattern) return false;
                }
            }
            return true;
        }
    };
};
